package com.zj.eswrapper.wrapper;

import cn.hutool.core.collection.CollectionUtil;
import com.zj.eswrapper.interfaces.impl.AbstractEsSearchWrapper;
import com.zj.eswrapper.model.Highlight;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.collapse.CollapseBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;

import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * es6分页以及排序等条件拼接器抽象类
 *
 * @author arthur_zhou
 * @date 2023/12/29 18:26
 */
public abstract class AbstractEsLastSearchWrapper<Field, SearchWrapper extends AbstractEsLastSearchWrapper<Field, SearchWrapper>>
        extends AbstractEsSearchWrapper<Field, SearchWrapper, SearchSourceBuilder> {

    public AbstractEsLastSearchWrapper(SearchSourceBuilder searchSourceBuilder) {
        super(searchSourceBuilder);
    }

    public AbstractEsLastSearchWrapper(AbstractEsSearchWrapper<?, ?, SearchSourceBuilder> searchWrapper) {
        super(searchWrapper);
    }

    @Override
    public SearchWrapper from(Integer from) {
        if (Objects.isNull(from)) {
            return child;
        }
        builder.from(from);
        return child;
    }

    @Override
    public SearchWrapper size(Integer size) {
        if (Objects.isNull(size)) {
            return child;
        }
        builder.size(size);
        return child;
    }

    @Override
    public SearchWrapper limit(Integer from, Integer size) {
        from(from);
        size(size);
        return child;
    }

    @Override
    public SearchWrapper orderByAsc(Object missing, Collection<String> fields) {
        for (String field : fields) {
            builder.sort(
                    new FieldSortBuilder(field).missing(missing).order(SortOrder.ASC)
            );
        }
        return child;
    }

    @Override
    public SearchWrapper orderByDesc(Object missing, Collection<String> fields) {
        for (String field : fields) {
            builder.sort(
                    new FieldSortBuilder(field).missing(missing).order(SortOrder.DESC)
            );
        }
        return child;
    }

    @Override
    public SearchWrapper trackTotalHits(Boolean enabled) {
        if (Objects.isNull(enabled)) {
            return child;
        }
        builder.trackTotalHits(enabled);
        return child;
    }

    @Override
    public SearchWrapper trackTotalHits(Integer count) {
        if (Objects.isNull(count)) {
            return child;
        }
        builder.trackTotalHitsUpTo(count);
        return child;
    }

    @Override
    public SearchWrapper collapse(Field field) {
        return customSearch(v -> v.collapse(new CollapseBuilder(getField(field))));
    }

    @Override
    public void addSearch(SearchSourceBuilder searchBuilder) {
        List<String> noSelectList = limit.getNoSelectList();
        List<String> selectList = limit.getSelectList();
        // 展示字段
        if (CollectionUtil.isNotEmpty(selectList) || CollectionUtil.isNotEmpty(noSelectList)) {
            String[] includes = CollectionUtil.isNotEmpty(selectList) ? selectList.toArray(new String[0]) : null;
            String[] excludes = CollectionUtil.isNotEmpty(noSelectList) ? selectList.toArray(new String[0]) : null;
            searchBuilder.fetchSource(includes, excludes);
        }
        // 高亮
        if (CollectionUtil.isNotEmpty(limit.getHighlightList())) {
            HighlightBuilder highlightBuilder = new HighlightBuilder();
            // 去重，以最后一个重复的名称为准
            limit.getHighlightList().stream().collect(Collectors.toMap(
                    Highlight::getField,
                    v -> v,
                    (v1, v2) -> v2
            )).forEach((field, highlight) -> {
                if (Objects.nonNull(highlight.getFragmentSize())) {
                    if (Objects.nonNull(highlight.getNumberOfFragments())) {
                        highlightBuilder.field(highlight.getField(), highlight.getFragmentSize(), highlight.getNumberOfFragments());
                    } else {
                        highlightBuilder.field(highlight.getField(), highlight.getFragmentSize());
                    }
                } else {
                    highlightBuilder.field(highlight.getField());
                }
            });
            if (CollectionUtil.isNotEmpty(limit.getHighlightPreTags())) {
                highlightBuilder.preTags(limit.getHighlightPreTags().toArray(new String[0]));
            }
            if (CollectionUtil.isNotEmpty(limit.getHighlightPostTags())) {
                highlightBuilder.postTags(limit.getHighlightPostTags().toArray(new String[0]));
            }
            searchBuilder.highlighter(highlightBuilder);
        }
    }

}
